#pragma once
#include "shader.hpp"
#include <initializer_list>

namespace opengl {

class program {
public:
    using shader_list = std::initializer_list<shader>;

    /* Constructors */
    OPENGLAPI program(); // Declare an empty program but does not create it
    OPENGLAPI program(const program &) = delete;
    OPENGLAPI program(program &&other);     // Move constructor
    OPENGLAPI program(shader_list shaders); // Create and link a program with a
                                            // list of shaders
    OPENGLAPI void create(shader_list shaders);
    
    /* Member functions */
    OPENGLAPI void attach_shader(const shader &shader) const; // Attach a shader to the program
    OPENGLAPI void attach_shaders(shader_list shaders) const;
    OPENGLAPI bool link() const;             // Link the program
    OPENGLAPI std::string get_error() const; // Check if there was an error during linking
    OPENGLAPI void use() const;              // Use the program for rendering

    /* Operators */
    OPENGLAPI program &operator=(const program &) = delete; // Copy assignment
    OPENGLAPI program &operator=(program &&other);          // Move assignment operator

    /* Destructor */
    OPENGLAPI ~program(); // Delete the program if it was created

public:
    /* Uniform variables */
    i32 get_uniform_location(const char *name) const;
    void set_mat2f(u32 location, const f32 *value, bool transposed = false) const;
    void set_mat3f(u32 location, const f32 *value, bool transposed = false) const;
    void set_mat4f(u32 location, const f32 *value, bool transposed = false) const;
    void set_vec2f(u32 location, const f32 *value) const;
    void set_vec3f(u32 location, const f32 *value) const;
    void set_vec4f(u32 location, const f32 *value) const;
    void set_int32(u32 location, i32 value) const;
    void set_uint32(u32 location, u32 value) const;
    void set_int64(u32 location, i64 value) const;
    void set_uint64(u32 location, u64 value) const;
    void set_float32(u32 location, f32 value) const;
    void set_float64(u32 location, f64 value) const;

public:
    u32 id;
};

} // namespace opengl